﻿using IdeaNMR.Web.Core;
using System;
using IdeaNMR.Shared;
using System.Web.UI.WebControls;
using Microsoft.Security.Application;
using System.Web.UI;

namespace IdeaNMR.Web
{
    public abstract class DesignBaseObject_BasePage<T> : IdeaNMR_BasePage
        where T : BaseObject, new()
    {
        protected abstract string PageTitle
        {
            get;
            set;
        }
        private BaseObjectFacade<T> _EntityFacade;
        protected BaseObjectFacade<T> EntityFacade
        {
            get
            {
                if (this._EntityFacade == null)
                    this._EntityFacade = ViewState["EntityFacade"] as BaseObjectFacade<T>;
                return this._EntityFacade;
            }
            set
            {
                ViewState["EntityFacade"] = this._EntityFacade = value;
            }
        }

        #region Page LifeCycle
        protected override void Page_Init(object sender, EventArgs e)
        {
            base.Page_Init(sender, e);

            if (!Page.IsPostBack)
            {
                SetValidationParameters();
            }
        }

        protected virtual void Page_PreLoad(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                this.InitiateObject();
            }
        }
        #region Control Events
        protected void butDraft_Click(object sender, EventArgs e)
        {
            this.CollectFormData();
            this.SaveData(true);
            this.ActualizePageTitle();
        }
        protected virtual void butOk_Click(object sender, EventArgs e)
        {
            this.CollectFormData();
            this.SaveData(false);
            this.SavePanel(false);
            this.UpdateButtonsState();
            this.ActualizePageTitle();
        }
        /// <summary>
        /// Makes saving panel visible.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void butSave_Click(object sender, EventArgs e)
        {
            SavePanel(true);
        }
        /// <summary>
        /// Cancel button closes saving panel.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void butCancel_Click(object sender, EventArgs e)
        {
            SavePanel(false);
        }

        #region SaveOption radio checked & Validation
        /// <summary>
        /// Switches the version info textarea, so when it is not required it is desabled.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void rbSaveOption_CheckChanged(object sender, EventArgs e)
        {
            tbVersionInfo.Enabled = rbVersion.Checked;
        }
        /// <summary>
        /// Only one radio button must be checked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks>БЫДЛО стиль! Probably this can never fail, but if user tryes to handmade the request.</remarks>
        protected void SaveOption_Validate(object sender, ServerValidateEventArgs e)
        {
            e.IsValid = rbVersion.Checked ^ rbNew.Checked;
        }
        #endregion
        #endregion
        protected virtual void Page_PreRender(object sender, EventArgs e)
        {
            UpdateVersionsList();
            if (!Page.IsPostBack)
            {
                UpdateFormData();
                UpdateButtonsState();
            }
        }
        protected virtual void Page_PreRenderComplete(object sender, EventArgs e)
        {
            this.PageTitle = this.TargetID.HasValue
                                 ? string.Format("{0} - {1}. {2}",
                                     AntiXss.HtmlEncode(this.EntityFacade.EntityObject.Name),
                                     this.EntityFacade.EntityObject.GetEntityType().ToCategoryName(),
                                     this.EntityFacade.EntityObject.IsDraft ? "(draft)" : string.Empty)
                                 : string.Format("Add New {0}.", this.EntityFacade.EntityObject.GetEntityType().ToCategoryName());

        }
        #endregion

        /// <summary>
        ///  Initiates EntityFacade with correct type.
        /// </summary>
        protected abstract void InitiateObject();

        // ALISTAIR: Comments added 09/07/2011
        // Retrieve info from the web form
        protected virtual void CollectFormData()
        {
            var obj = this.EntityFacade.EntityObject;

            // experiment name given by user
            obj.Name = this.tbName.Text;
            // "remarks" text given by user
            obj.Info = this.tbMemo.Text;
            // contents of the "scipt" tab entered by the user
            obj.Script = this.tbScript.Text;

            // make the object private by default
            obj.IsPrivate = true;

            // check if the user has specified the pulse program
            if (rbNew.Checked)
            {
                // the current object become the first version
                // of the new pulse program
                obj.VersionInfo = "First Version.";
                obj.FirstVersion = obj;
            }
            else
            {
                // set the version info to the text
                // specified by the user for the new version
                obj.VersionInfo = this.tbVersionInfo.Text;
            }

            // indicate that data has been updated
            this.DataIsUpdated = true;
        }

        protected virtual void UpdateFormData()
        {
            T obj = this.EntityFacade.EntityObject;

            this.tbName.Text = obj.Name;
            this.tbMemo.Text = obj.Info;
            this.tbScript.Text = obj.Script;
            this.tbVersionInfo.Text = obj.VersionInfo;
        }
        /// <summary>
        /// Sets the parameters of Validation controls to those specified in 
        /// <see cref="IdeaNMR.Shared.Sanitar"/> class.
        /// </summary>
        /// <remarks>You can override this method if you have more 
        /// validation controls.</remarks>
        protected virtual void SetValidationParameters()
        {
            this.tbName.MaxLength = Sanitar.Name.MaxLength;
            this.revName.Text = this.rfvName.Text = Sanitar.Name.ErrorMsg;
            this.revName.ValidationExpression = Sanitar.Name.ValidationRegex;

            this.tbMemo.MaxLength = Sanitar.Remark.MaxLength;
            this.rfvMemo.Text = this.revMemo.Text = Sanitar.Remark.ErrorMsg;
            this.revMemo.ValidationExpression = Sanitar.Remark.ValidationRegex;

            this.tbScript.MaxLength = Sanitar.Script.MaxLength;
            this.revScript.Text = Sanitar.Script.ErrorMsg;
            this.revScript.ValidationExpression = Sanitar.Script.ValidationRegex;

            this.tbVersionInfo.MaxLength = Sanitar.Remark.MaxLength;
            this.revVersionInfo.Text = Sanitar.Remark.ErrorMsg;
            this.revVersionInfo.ValidationExpression = Sanitar.Remark.ValidationRegex;
        }
        protected virtual void ActualizePageTitle()
        {
            this.PageTitle = string.Format("{0} - {1}. {2}",
                                     AntiXss.HtmlEncode(this.EntityFacade.EntityObject.Name),
                                     this.EntityFacade.EntityObject.GetEntityType().ToCategoryName(),
                                     this.EntityFacade.EntityObject.IsDraft ? "(draft)" : string.Empty);
        }


        protected void UpdateButtonsState()
        {
            var obj = this.EntityFacade.EntityObject;

            //         if (obj.Id == Guid.Empty || !isUserAnAuthor(obj))
            if (obj.Id == Guid.Empty || !this.EntityFacade.isUserAnAuthor(ScrewTurnWikiFacade.Username))
            {
                this.rbNew.Checked = true;
                this.rbVersion.Checked = false;
                this.tbVersionInfo.Enabled = false;
                this.rbVersion.Enabled = false;
            }
            else
            {
                this.rbVersion.Checked = true;
                this.rbVersion.Enabled = true;
                this.rbNew.Checked = false;
                this.tbVersionInfo.Enabled = true;
            }
        }

        #region Page Controls Declarations
        protected global::System.Web.UI.WebControls.Button butDraft;
        protected global::System.Web.UI.WebControls.Button butSave;
        protected global::System.Web.UI.WebControls.Label lblSysMsg;

        protected global::System.Web.UI.WebControls.Panel panSave;
        protected global::System.Web.UI.WebControls.RadioButton rbNew;
        protected global::System.Web.UI.WebControls.RadioButton rbVersion;
        protected global::System.Web.UI.WebControls.TextBox tbVersionInfo;
        protected global::System.Web.UI.WebControls.RegularExpressionValidator revVersionInfo;

        protected global::System.Web.UI.WebControls.CheckBox chkPublic;

        protected global::System.Web.UI.WebControls.TextBox tbScript;
        protected global::System.Web.UI.WebControls.RegularExpressionValidator revScript;

        protected global::System.Web.UI.WebControls.TextBox tbMemo;
        protected global::System.Web.UI.WebControls.RequiredFieldValidator rfvMemo;
        protected global::System.Web.UI.WebControls.RegularExpressionValidator revMemo;

        protected global::System.Web.UI.WebControls.TextBox tbName;
        protected global::System.Web.UI.WebControls.RequiredFieldValidator rfvName;
        protected global::System.Web.UI.WebControls.RegularExpressionValidator revName;
        #endregion

        /// <summary>
        /// Makes the panel with save options visible or hidden.
        /// </summary>
        /// <param name="open">If true - visible, else hidden.</param>
        protected void SavePanel(bool open)
        {
            panSave.Visible = open;
            butSave.Enabled = !open;
            butDraft.Enabled = !open;
        }

        // ALISTAIR: Comments added 09/07/2011
        // save the web form data 
        protected void SaveData(bool isDraft)
        {
            // check if the current web form data has been collected
            if (!this.DataIsUpdated)
                throw new InvalidOperationException("SaveData requires CollectFormData to be called before it.");

            SaveModeOptions smo;

            // set the save mode
            if (isDraft)
            {
                smo = SaveModeOptions.Draft;
            }
            else
            {
                // if the "Make It Public" button was checked
                // then set save mode to public, otherwise
                // set save mode to private
                smo = chkPublic.Checked
                        ? SaveModeOptions.Public
                        : SaveModeOptions.Private;
            }

            if (this.EntityFacade.SaveChanges(tbVersionInfo.Text, smo, rbVersion.Checked))
            {
                lblSysMsg.Visible = true;
                // record the current timestamp for the save 
                lblSysMsg.Text = string.Format("Saved on {0}.", DateTime.Now.ToString(ScrewTurnWikiFacade.DateTimeFormat));
            }

            this.DataIsUpdated = false;
        }

        /// <summary>
        /// Indicates that Form data was collected since last save operation.
        /// </summary>
        private bool DataIsUpdated { get; set; }

        #region Versions List
        protected global::IdeaNMR.Web.VersionList Versions;

        protected void UpdateVersionsList()
        {
            var obj = this.EntityFacade.EntityObject;

            this.Versions.Versions = obj.FirstVersion.DerivedVersions;
        }
        #endregion

        /// <summary>
        /// A Guid of HardObject to display.
        /// </summary>
        /// <exception cref="System.InvalidCastException">When ViewState["TargetID"] does not contain valid Guid.</exception>
        /// <exception cref="System.InvalidOperationException">When ViewState["TargetID"] conteins Guid.Empty.</exception>
        protected Guid? TargetID
        {
            get
            {
                // If ViewState is already contains Guid
                object o = ViewState["TargetID"];
                if (o == null) return null;

                Guid res = Guid.Empty;
                if (o is Guid)
                    res = (Guid)o;
                else
                {
                    try
                    {
                        res = new Guid(o.ToString());
                        ViewState["TargetID"] = res;
                        return res;
                    }
                    catch (FormatException ex)
                    {
                        throw new ApplicationException("TargetID is not a valid Guid.", ex);
                    }
                    catch (OverflowException ex)
                    {
                        throw new ApplicationException("TargetID is not a valid Guid.", ex);
                    }
                }

                if (res == Guid.Empty)
                    throw new ApplicationException("TargetID should not be string.Empty.");

                return res;
            }
        }
    }
}